import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef, useState } from 'react';
// import './userWorker';
import * as monaco from 'monaco-editor/esm/vs/editor/editor.api';
import 'monaco-editor/esm/vs/basic-languages/monaco.contribution';
import 'monaco-editor/esm/vs/language/json/monaco.contribution';
import 'monaco-editor/esm/vs/language/css/monaco.contribution';

// import cssConfig from './cssConfig';

export interface EditorProp {
  readOnly?: boolean;
  language?: 'json' | 'css' | 'javascript';
  value?: string;
  onError?: (err) => void;
  onCancel: () => void;
  onOk: () => void;
}

let saveAction;

// 自定义代码提示
// function createCssProposals(range) {
//   // returning a static list of proposals, not even looking at the prefix (filtering is done by the Monaco editor),
//   // here you could do a server side lookup
//   return cssConfig.map((item) => ({
//     ...item,
//     kind: monaco.languages.CompletionItemKind.Property,
//     // insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
//     range,
//   }));
// }

// monaco.languages.registerCompletionItemProvider('json', {
//   provideCompletionItems: (model, position) => {
//     // find out if we are completing a property in the 'dependencies' object.
//     const textUntilPosition = model.getValueInRange({
//       startLineNumber: 1,
//       startColumn: 1,
//       endLineNumber: position.lineNumber,
//       endColumn: position.column,
//     });
//     const match = textUntilPosition.match(
//       /\{\s*("[^"]*"\s*:\s*"[^"]*"\s*,\s*)*([^"]*)?$/
//     );
//     console.log('textUntilPosition', textUntilPosition)
//     if (!match) {
//       return { suggestions: [] };
//     }
//     const word = model.getWordUntilPosition(position);
//     console.log('word', word)
//     const range = {
//       startLineNumber: position.lineNumber,
//       endLineNumber: position.lineNumber,
//       startColumn: word.startColumn,
//       endColumn: word.endColumn,
//     };
//     return {
//       suggestions: createCssProposals(range),
//     };
//   },
// });

export default forwardRef(function Editor(props: EditorProp, ref) {
  const { language = 'json', value, onError, onCancel, onChange, onOk, readOnly } = props as any;
  const [editor, setEditor] = useState<monaco.editor.IStandaloneCodeEditor | null>(null);
  const monacoEl = useRef(null);

  useEffect(() => {
    if (monacoEl && !editor) {
      // console.log('props.value：', props.value);
      const ed = monaco.editor.create(monacoEl.current!, {
        value,
        language,
        // acceptSuggestionOnCommitCharacter: true, // 接受关于提交字符的建议
        // acceptSuggestionOnEnter: 'on', // 接受输入建议 "on" | "off" | "smart"
        // accessibilityPageSize: 10, // 辅助功能页面大小 Number 说明：控制编辑器中可由屏幕阅读器读出的行数。警告：这对大于默认值的数字具有性能含义。
        // accessibilitySupport: 'on', // 辅助功能支持 控制编辑器是否应在为屏幕阅读器优化的模式下运行。
        autoClosingBrackets: 'always', // 是否自动添加结束括号(包括中括号) "always" | "languageDefined" | "beforeWhitespace" | "never"
        autoClosingDelete: 'always', // 是否自动删除结束括号(包括中括号) "always" | "never" | "auto"
        // autoClosingOvertype: 'always', // 是否关闭改写 即使用insert模式时是覆盖后面的文字还是不覆盖后面的文字 "always" | "never" | "auto"
        // autoClosingQuotes: 'always', // 是否自动添加结束的单引号 双引号 "always" | "languageDefined" | "beforeWhitespace" | "never"
        // autoIndent: 'none', // 控制编辑器在用户键入、粘贴、移动或缩进行时是否应自动调整缩进
        // automaticLayout: true, // 自动布局
        // codeLens: false, // 是否显示codeLens 通过 CodeLens，你可以在专注于工作的同时了解代码所发生的情况 – 而无需离开编辑器。 可以查找代码引用、代码更改、关联的 Bug、工作项、代码评审和单元测试。
        // codeLensFontFamily: '', // codeLens的字体样式
        // codeLensFontSize: 14, // codeLens的字体大小
        // colorDecorators: false, // 呈现内联色彩装饰器和颜色选择器
        // comments: {
        //     ignoreEmptyLines: true, // 插入行注释时忽略空行。默认为真。
        //     insertSpace: true // 在行注释标记之后和块注释标记内插入一个空格。默认为真。
        // }, // 注释配置
        // contextmenu: true, // 启用上下文菜单
        // columnSelection: false, // 启用列编辑 按下shift键位然后按↑↓键位可以实现列选择 然后实现列编辑
        // autoSurround: 'never', // 是否应自动环绕选择
        // copyWithSyntaxHighlighting: true, // 是否应将语法突出显示复制到剪贴板中 即 当你复制到word中是否保持文字高亮颜色
        // cursorBlinking: 'solid', // 光标动画样式
        // cursorSmoothCaretAnimation: true, // 是否启用光标平滑插入动画  当你在快速输入文字的时候 光标是直接平滑的移动还是直接"闪现"到当前文字所处位置
        // cursorStyle: 'underline-thin', // "Block"|"BlockOutline"|"Line"|"LineThin"|"Underline"|"UnderlineThin" 光标样式
        // cursorSurroundingLines: 0, // 光标环绕行数 当文字输入超过屏幕时 可以看见右侧滚动条中光标所处位置是在滚动条中间还是顶部还是底部 即光标环绕行数 环绕行数越大 光标在滚动条中位置越居中
        // cursorSurroundingLinesStyle: 'all', // "default" | "all" 光标环绕样式
        // cursorWidth: 2, // <=25 光标宽度
        // minimap: {
        //     enabled: false // 是否启用预览图
        // }, // 预览图设置
        fontSize: 12,
        // foldingStrategy: 'indentation',
        // folding: true, // 是否启用代码折叠
        // links: true, // 是否点击链接
        // overviewRulerBorder: false, // 是否应围绕概览标尺绘制边框
        // renderLineHighlight: 'gutter', // 当前行突出显示方式
        // roundedSelection: false, // 选区是否有圆角
        // scrollBeyondLastLine: false, // 设置编辑器是否可以滚动到最后一行之后
        readOnly, // 是否为只读模式
        // theme: 'vs',// vs, hc-black, or vs-dark
        contextmenu: false, // 临时解决右键崩溃的问题 TODO
      });
      setEditor(ed);

      // ESC 取消事件
      ed.addCommand(monaco.KeyCode.Escape, function() {
        onCancel();
      });

      monaco.editor.onDidChangeMarkers((e) => {
        const m = monaco.editor.getModelMarkers({ resource: e[0] });
        // if (m[0] && m[0].code === '1109') {
        onError && onError(m[0]);
        // }
      });

      ed.onDidChangeModelContent((e) => {
        onChange && onChange(ed.getValue())
      });
    }
    return () => editor?.dispose();
  }, [monacoEl.current]);

  useEffect(() => {
    value && editor?.setValue(value as string);
  }, [value]);

  // CTRL + S 保存事件
  useEffect(() => {
    if (editor) {
      if (saveAction) {
        saveAction.dispose();
      }

      saveAction = editor.addAction({
        // An unique identifier of the contributed action.
        id: 'ctrl+s',
        // A label of the action that will be presented to the user.
        label: '保存',
        // An optional array of keybindings for the action.
        keybindings: [monaco.KeyMod.CtrlCmd | monaco.KeyCode.KeyS],
        // A precondition for this action.
        precondition: undefined,
        // A rule to evaluate on top of the precondition in order to dispatch the keybindings.
        keybindingContext: undefined,
        contextMenuGroupId: 'navigation',
        contextMenuOrder: 1.5,
        // Method that will be executed when the action is triggered.
        // @param editor The editor instance is passed in as a convenience
        run: (ed) => {
          onOk();
        },
      });
    }
  }, [editor, onOk]);

  useImperativeHandle(ref, () => ({
    getValue: () => editor?.getValue(),
  }));

  return <div style={{ width: '100%', height: '100%' }} ref={monacoEl}></div>;
});
